﻿/*
 * KRPCParameterInfo
 * 
 * Represents the parameter of KRPCOperation
 * 
 * KRPCParameter
 * 
 * Represents an instance of krpc parameter
 * 
 * Author: snowdreamist
 * Date: 2011/12/11
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using BitTorrentSharp.KRPC.Contract;

namespace BitTorrentSharp.KRPC
{
    public enum ParameterDirection
    {
        /// <summary>
        /// Normal
        /// </summary>
        In,
        /// <summary>
        /// out
        /// </summary>
        Out,
        /// <summary>
        /// ref
        /// </summary>
        Both
    }

    public class KRPCParameterInfo
    {
        internal KRPCParameterInfo(ParameterInfo paraInfo)
        {
            if (paraInfo == null)
                throw new ArgumentNullException("paraInfo");
            // get info
            this.ParameterName = paraInfo.Name;
            // direction
            if (paraInfo.IsOut)
                this.Direction = ParameterDirection.Out;
            else if (paraInfo.ParameterType.IsByRef)
                this.Direction = ParameterDirection.Both;
            else
                this.Direction = ParameterDirection.In;
            // pos
            this.Position = paraInfo.Position;
            // type
            this.Type = KRPCDataInfo.GetDataInfo(paraInfo.ParameterType);
            // TODO is by ref
            // get attribute
            var attrs = paraInfo.GetCustomAttributes(typeof(KRPCParameterContractAttribute), false);
            if (attrs == null || attrs.Length == 0)
                this.Wrapper = new ParameterContractWrapper();
            else
                this.Wrapper = new ParameterContractWrapper(attrs[0] as KRPCParameterContractAttribute);
            if (string.IsNullOrWhiteSpace(this.Wrapper.ContractName))
                this.ContractName = this.ParameterName;
            else
                this.ContractName = this.Wrapper.ContractName;
        }
        /// <summary>
        /// Wrapper
        /// </summary>
        public ParameterContractWrapper Wrapper { get; private set; }
        /// <summary>
        /// Contract name
        /// </summary>
        public string ContractName { get; private set; }
        /// <summary>
        /// Parameter name
        /// </summary>
        public string ParameterName { get; private set; }
        /// <summary>
        /// Is by ref
        /// </summary>
        public bool IsByRef { get; private set; }
        /// <summary>
        /// Direction
        /// </summary>
        public ParameterDirection Direction { get; private set; }
        /// <summary>
        /// Position in arguments list
        /// </summary>
        public int Position { get; private set; }
        /// <summary>
        /// Type
        /// </summary>
        public KRPCDataInfo Type { get; private set; }
    }

    public class KRPCParameter : KRPCData
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="info">KRPCParameterInfo</param>
        public KRPCParameter(KRPCParameterInfo info)
            : base(info.Type, info.ContractName)
        {
            if (info == null)
                throw new ArgumentNullException("info");
            this.Info = info;
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="info">KRPCParameterInfo</param>
        /// <param name="value">parameter value, could be null</param>
        public KRPCParameter(KRPCParameterInfo info, object value)
            : base(info.Type, info.ContractName, value)
        {
            if (info == null)
                throw new ArgumentNullException("info");
            this.Info = info;
        }
        /// <summary>
        /// Parameter info
        /// </summary>
        public KRPCParameterInfo Info { get; private set; }
    }
}
